#include "StdAfx.h"
#include "global.h"
#include "symtab.h"
#include "code.h"
#include "cgen.h"

cgen::cgen(void)
{
}

cgen::~cgen(void)
{
}

static int LabelIndex=0;
static int TempIndex=1;
static int CodeLine=1;

static int NewLabel()
{
	return ++LabelIndex;
}
/* Procedure genStmt generates code at a statement node */
void cgen::genStmt(TreeNode * tree,CodeStruct * S)
{ 
	TreeNode * p1, * p2, * p3;
	char * str1;
	char * name;
	CodeStruct E,E1,E2;
	switch(tree->kind.stmt)
	{
	case IfK:		
		p1 = tree->child[0] ;
		p2 = tree->child[1] ;
		p3 = tree->child[2] ;
		
		E.LTrue=NewLabel();
		if(p3 == NULL)
		{
			E.LFalse=S->LNext;
			E1.LNext=S->LNext;
			E.is_stmt=1;
			genExp(p1,&E);
			if(p2!=NULL)
				fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,E.LTrue);
			cGen(p2,&E1);
		}
		else
		{		
			E.LFalse=NewLabel();
			E.is_stmt=1;
			E1.LNext=S->LNext;
			E2.LNext=S->LNext;
			genExp(p1,&E);
			if(p1!=NULL)
				fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,E.LTrue);
			cGen(p2,&E1);
			fprintf(global::code,"(%d)goto L%d\r\n",CodeLine++,S->LNext);	
			if(p2!=NULL)
				fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,E.LFalse);
			cGen(p3,&E2);
		}
		break;

	case RepeatK:
		p1=tree->child[0];
		p2=tree->child[1];	
		
		S->LBegin=NewLabel();
		E1.LNext=NewLabel();
		E.LTrue=S->LNext;
		E.LFalse=S->LBegin;
		E.is_stmt=1;
		if(p1!=NULL)
			fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,S->LBegin);
		cGen(p1,&E1);
		fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,E1.LNext);
		genExp(p2,&E);		
		break;			/* repeat */	

	case AssignK:
		str1 = cGen(tree->child[0],S);
		fprintf (global::code, "(%d)%s:=%s\r\n", CodeLine++,tree->attr.name, str1);
		break;			/* assign_k */	

	case ReadK:
		fprintf (global::code, "(%d)read %s\r\n", CodeLine++,tree->attr.name);
		break;

	case WriteK:
		str1 = cGen(tree->child[0],S);
		fprintf (global::code, "(%d)write %s\r\n", CodeLine++,str1);
		break;
		/************************************************************************/
	case WhileK:
		p1=tree->child[0];
		p2=tree->child[1];
		E.is_stmt=1;
		S->LBegin=NewLabel();
		E.LTrue=NewLabel();
		E.LFalse=S->LNext;
		E1.LNext=S->LBegin;
		fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,S->LBegin);
		genExp(p1,&E);
		if(p2!=NULL)
			fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,E.LTrue);
		cGen(p2,&E1);
		fprintf(global::code,"(%d)goto L%d\r\n",CodeLine++,S->LBegin);
		break;
		/************************************************************************/
	default:
		break;
	}
} /* genStmt */

/* Procedure genExp generates code at an expression node */
char * cgen::genExp(TreeNode * tree,CodeStruct * S)
{ 
	TreeNode * p1, * p2;
	char *str1,*str2;
	char *str=new char(20);
	CodeStruct E1,E2;
	switch (tree->kind.exp)
	{		
    case ConstK :
		sprintf (str, "%d", tree->attr.val);
		break;/* ConstK */
	case StringK:/*String*/
    case IdK :
		strcpy(str,tree->attr.name);
		break; /* IdK */
	case OpK:
		p1 = tree->child[0];
		p2 = tree->child[1];				
		switch (tree->attr.op) 
		{
		case AND:				
			E1.LTrue=NewLabel();
			E1.LFalse=S->LFalse;
			E2.LTrue=S->LTrue;
			E2.LFalse=S->LFalse;
			E1.is_stmt=1;
			E2.is_stmt=1;
			str1=genExp(p1,&E1);
			fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,E1.LTrue);
			str2=genExp(p2,&E2);
			break;
		case OR:
			E1.LTrue=S->LTrue;
			E1.LFalse=NewLabel();
			E2.LTrue=S->LTrue;
			E2.LFalse=S->LFalse;
			str1=genExp(p1,&E1);
			fprintf(global::code,"(%d)Label L%d\r\n",S->LFalse);
			str2=genExp(p2,&E2);			
			break;
		case NOT:
			E1.LTrue=S->LFalse;
			E1.LFalse=S->LTrue;
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			break;
		case GT:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			if(S->is_stmt==1)
			{				
				fprintf(global::code,"(%d)if %s > %s goto L%d\r\n",CodeLine++,str1,str2,S->LTrue);
				fprintf(global::code,"(%d)goto L%d\r\n",CodeLine++,S->LFalse);
			}
			else
				fprintf(global::code,"(%d)t%d = %s > %s\r\n",CodeLine++,TempIndex++,str1,str2);
			break;
		case LT:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			if(S->is_stmt==1)
			{
				fprintf(global::code,"(%d)if %s < %s goto L%d\r\n",CodeLine++,str1,str2,S->LTrue);
				fprintf(global::code,"(%d)goto L%d\r\n",CodeLine++,S->LFalse);
			}
			else
			{	
				fprintf(global::code,"(%d)t%d = %s < %s\r\n",CodeLine++,TempIndex++,str1,str2);
			}
			break;
		case EQ:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			if(S->is_stmt==1)
			{
				fprintf(global::code,"(%d)if %s = %s goto L%d\r\n",CodeLine++,str1,str2,S->LTrue);
				fprintf(global::code,"(%d)goto L%d\r\n",CodeLine++,S->LFalse);
			}
			else
				fprintf(global::code,"(%d)t%d = %s =  %s\r\n",CodeLine++,TempIndex++,str1,str2);
			break;
		case GET:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			if(S->is_stmt==1)
			{
				fprintf(global::code,"(%d)if %s >= %s goto L%d\r\n",CodeLine++,str1,str2,S->LTrue);
				fprintf(global::code,"(%d)goto L%d\r\n",CodeLine++,S->LFalse);
			}
			else
				fprintf(global::code,"(%d)t%d = %s >= %s\r\n",CodeLine++,TempIndex++,str1,str2);
			break;
		case LET:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			if(S->is_stmt==1)
			{
				fprintf(global::code,"(%d)if %s <= %s goto L%d\r\n",CodeLine++,str1,str2,S->LTrue);
				fprintf(global::code,"(%d)goto L%d\r\n",CodeLine++,S->LFalse);
			}
			else
				fprintf(global::code,"(%d)t%d =%s <= %s\r\n",CodeLine++,TempIndex++,str1,str2);
			break;
		case PLUS:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			fprintf(global::code,"(%d)t%d := %s + %s\r\n",CodeLine++,TempIndex++,str1,str2);
			break;
		case MINUS:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			fprintf(global::code,"(%d)t%d := %s - %s\r\n",CodeLine++,TempIndex++,str1,str2);
			break;
		case TIMES:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			fprintf(global::code,"(%d)t%d := %s * %s\r\n",CodeLine++,TempIndex++,str1,str2);
			break;
		case OVER:
			str1=genExp(p1,&E1);
			str2=genExp(p2,&E2);
			fprintf(global::code,"(%d)t%d := %s / %s\r\n",CodeLine++,TempIndex++,str1,str2);
			break;
		}	 
		sprintf (str, "%s%d", "t", TempIndex);
		break;
	}
	char * str3 = new char(20);
	sprintf (str3, "%s%d", "t", TempIndex);
	if (str[0]==str3[0] && str[1]==str3[1]){
		sprintf (str3, "%s%d", "t", --TempIndex);
		str=str3;
		TempIndex++;
	}
	return str;
} /* genExp */

/* Procedure cGen recursively generates code by
 * tree traversal
 */
char * cgen::cGen( TreeNode * tree,CodeStruct *Lcode)
{ 
	char * str=NULL;
	CodeStruct E,E1;
	if (tree != NULL)
	{ 
		switch (tree->nodekind) {
		case StmtK:
			switch(tree->kind.stmt)
			{
			case ProgramK:
				cGen(tree->child[1],&E);
				break;
			case RepeatK:
			case WhileK:		
			case IfK:
			case AssignK:
			case ReadK:
			case WriteK:
				E.LNext=NewLabel();
				E1.LNext=Lcode->LNext;
				genStmt(tree,&E);
//				if(tree->kind.stmt!=ReadK && tree->kind.stmt!=AssignK && tree->kind.stmt!=WriteK)
				fprintf(global::code,"(%d)Label L%d\r\n",CodeLine++,E.LNext);
				break;
			}
			break;
			case ExpK:
				str=genExp(tree,Lcode);
				break;
			default:
				break;
		}
		cGen(tree->sibling,&E1);
	}
	return str;
}

/**********************************************/
/* the primary function of the code generator */
/**********************************************/
/* Procedure codeGen generates code to a code
 * file by traversal of the syntax tree. The
 * second parameter (codefile) is the file name
 * of the code file, and is used to print the
 * file name as a comment in the code file
 */
void cgen::codeGen(TreeNode * syntaxTree)
{ 
	CodeStruct Lcode;
	Lcode.LBegin=LabelIndex;
	Lcode.LNext=LabelIndex;
	Lcode.LTrue=LabelIndex;
	Lcode.LFalse=LabelIndex;
	cGen(syntaxTree,&Lcode);
}
